package cevent.source.cloudcenter.business.controller.admin;

import cevent.source.cloudcenter.server.dto.*;
import cevent.source.cloudcenter.server.service.EmployeeService;
import cevent.source.cloudcenter.server.util.UUID8Util;
import cevent.source.cloudcenter.server.util.ValidatorUtil;
import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author cevent
 * @description 员工管理表控制层
 */
@RestController
@RequestMapping("/admin/employee")
public class EmployeeController {
    private static final Logger LOG = LoggerFactory.getLogger(EmployeeController.class);
    //AOP日志环绕
    public static final String BUSINESS_NAME="模块管理 员工管理表";
    @Resource
    private EmployeeService employeeService;
    //注入redis
    @Resource
    private RedisTemplate redisTemplate;
    //1.dto-employee获取
    @RequestMapping("/dtoList")
    public List<EmployeeDto> getDtoList() {
        return employeeService.employeeDtoList();
    }

    //2.查询所有员工信息
    @RequestMapping("/list")
    public ResponseDataDto list(){
        ResponseDataDto responseData=new ResponseDataDto();
        List<EmployeeDto> responseDataDtoList=employeeService.allList();
        responseData.setResponseData(responseDataDtoList);
        return responseData;
    }

    /*2.前端分页设置，后端pageInfo处理
    前端传参方式一：表单方式--》formData 前端：直接传对象   后端参数：(Dto对象)
    前端传参方式二：流的方式--》data{param1:value1,param2:vlaue2}  后端参数：(@RequestBody Dto dto对象)
     */
    @PostMapping("/pageList")
    public ResponseDataDto list(@RequestBody PageDto pageDto) {
        LOG.info("查看controller的pageDto：{}", pageDto);
        ResponseDataDto responseData = new ResponseDataDto();
        employeeService.getEmployeePageDtoList(pageDto);
        responseData.setResponseData(pageDto);
        return responseData;
    }

    //3.新增，流方式传参，加入@RequestBody
    @PostMapping("/save")
    public ResponseDataDto save(@RequestBody EmployeeDto employeeDto) {
        LOG.info("传入的employee DTO的pwd：{}", employeeDto.getPassword());

        ValidatorUtil.requiredEmpty(employeeDto.getName(), "姓名");
        ValidatorUtil.requiredLength(employeeDto.getName(), "姓名", 2, 50);
        ValidatorUtil.requiredLength(employeeDto.getNickName(), "昵称", 2, 50);
        ValidatorUtil.requiredLength(employeeDto.getLoginName(), "登录名", 3, 255);
        ValidatorUtil.requiredLength(employeeDto.getPassword(), "密码", 6, 255);
        ValidatorUtil.requiredLength(employeeDto.getPosition(), "职位", 2, 50);
        //ValidatorUtil.requiredLength(employeeDto.getIcon(), "头像", 3, 255);
        //md5加密
        employeeDto.setPassword(DigestUtils.md5DigestAsHex(employeeDto.getPassword().getBytes()));
        LOG.info("二次加密的employee DTO的pwd：{}", employeeDto.getPassword());
        ResponseDataDto responseData = new ResponseDataDto();
        employeeService.save(employeeDto);
        responseData.setResponseData(employeeDto);
        return responseData;
    }

    /**
     * 指定请求的格式为Delete
     * 4.删除模块，如果为多个参数，就定义多个/{param}/{param}
     */
    @DeleteMapping("/del/{uniId}")
    public ResponseDataDto del(@PathVariable String uniId) {
        LOG.info("传入的employee uniId：{}", uniId);
        ResponseDataDto responseData = new ResponseDataDto();
        employeeService.delete(uniId);
        return responseData;
    }

    //5.保存密码
    @PostMapping("/save-pwd")
    public ResponseDataDto savePassword(@RequestBody EmployeeDto employeeDto){
        LOG.info("传入的密码：{}",employeeDto.getPassword());
        employeeDto.setPassword(DigestUtils.md5DigestAsHex(employeeDto.getPassword().getBytes()));
        LOG.info("加密的密码：{}",employeeDto.getPassword());
        ResponseDataDto responseData=new ResponseDataDto();
        EmployeeDto emp= employeeService.savePWD(employeeDto);
        responseData.setResponseData(emp);
        return responseData;
    }

    /**
     * 6.登录:注意前后端分离构架特性：每次用户端发送请求（验证码/登录）sessionId不同
     * 使用springboot+jsp或者springboot+thymeLeaf不会出现sessionId不同问题
     * 解决sessionId不同，需要在前端main.js设置axios配置credential证书:axios.defaults.withCredentials=true;
     * 可调整，取消redis存储，节省成本
     * @param employeeDto
     * @param request
     * @return
     */
    @PostMapping("/login")
    public ResponseDataDto loginEmp(@RequestBody EmployeeDto employeeDto, HttpServletRequest request){
        ResponseDataDto responseDataDto=new ResponseDataDto();
        //登录时，避免前后端密码暴露，对密码进行二次加密
        LOG.info("传入的密码：{}",employeeDto.getPassword());
        employeeDto.setPassword(DigestUtils.md5DigestAsHex(employeeDto.getPassword().getBytes()));
        LOG.info("加密的密码：{}",employeeDto.getPassword());
        //获取前端会话缓存session
        LOG.info("http servlet request传入的客户端主机名remoteHost：{} , 客户端IP remoteAddr：{}，客户端session：{},客户端sessionId：{}",
                request.getRemoteHost(),request.getRemoteAddr(),request.getSession(),request.getSession().getId());
        //根据imgCodeToken获取缓存中的验证码，判断与用户输入的验证码是否一致
        /**2.启用redis后注销*/
        /*String imgCodeToken=(String) request.getSession().getAttribute(employeeDto.getImgCodeToken());
        LOG.info("获取session-imgCodeToken（与redis相同key为UUID8位&&value为kaptcha生成的4位imgCode）：{}",imgCodeToken);*/

        //String imgCode=(String) request.getSession().getAttribute(employeeDto.getImgCode());

        //redis存储：获取图片验证码kaptcha根据前端uuid生成的imgCode(存储为key，get时，匹配value=createCode)
        /**2.不启用redis*/
        String imgCodeToken=(String)redisTemplate.opsForValue().get(employeeDto.getImgCodeToken());
        LOG.info("redis获取的imgCode Token：{}",imgCodeToken);
        //获取到的imgCodeToen为空
        if(StringUtils.isEmpty(imgCodeToken)){
            responseDataDto.setSuccess(false);
            responseDataDto.setResponseMsg("验证码已过期");
            LOG.info("验证码已过期，登录失败，验证码imgCodeToken：{}",imgCodeToken);
            return responseDataDto;
        }
        //获取到的imgCodeToken与前端传入的ImgCode不相等(不需要大小写判断，这里全转小写)
        LOG.info("imgCodeToken：{} ,getImgCode(){} ",imgCodeToken,employeeDto.getImgCode());
        if(!imgCodeToken.toLowerCase().equals(employeeDto.getImgCode().toLowerCase())){
            responseDataDto.setSuccess(false);
            responseDataDto.setResponseMsg("输入验证码错误，请重新输入");
            LOG.info("输入验证码错误,登录失败，验证码imgCodeToken：{}",imgCodeToken);
            return responseDataDto;
        }else{
            LOG.info("登录成功，验证码imgCodeToken：{}",imgCodeToken);
            request.getSession().removeAttribute(employeeDto.getImgCodeToken());
            //移除redis存储
            redisTemplate.delete(employeeDto.getImgCodeToken());
        }
        employeeDto.setLoginIp(request.getRemoteAddr());
        EmployeeLoginDto emp=employeeService.login(employeeDto);
        //生成唯一token，做redis、session记录，将token存入EmployeeLoginDto
        String token= UUID8Util.getShortUUID();
        emp.setToken(token);

        //将session放入dto，配置dto中的全局常量
        request.getSession().setAttribute(Constants.EMP_LOGIN_INFO,emp);

        //Todo 以token作为key，将login对象转为字符串存储，存储时间为1小时
        /**3.不启用redis*/
        //这里的3600s为未操作系统时（空闲时间），在gateway时进行刷新超时时间
        redisTemplate.opsForValue().set(token, JSON.toJSONString(emp),3600, TimeUnit.SECONDS);
        LOG.info("登录完毕token对象：{}",emp);

        //redis登录成功，放入session
        responseDataDto.setResponseData(emp);
        return responseDataDto;
    }
    //登出时，传递token，对redis进行删除数据
    @GetMapping("/loginOut/{token}")
    public ResponseDataDto loginOut(@PathVariable String token,HttpServletRequest request){
        ResponseDataDto responseDataDto=new ResponseDataDto();
        //将session清除
        request.getSession().removeAttribute(Constants.EMP_LOGIN_INFO);
        LOG.info("从session删除的login对象：{}",Constants.EMP_LOGIN_INFO);
        /**4.不启用redis*/
        redisTemplate.delete(token);
        LOG.info("从redis删除的token：{}",token);
        responseDataDto.setResponseData("已清空客户端session");
        return responseDataDto;
    }
}
